/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.sunspotworld.protocols;

import com.sun.spot.peripheral.ChannelBusyException;
import com.sun.spot.peripheral.NoAckException;
import com.sun.spot.peripheral.radio.IProtocolManager;
import com.sun.spot.peripheral.radio.IRadiogramProtocolManager;
import com.sun.spot.peripheral.radio.LowPan;
import com.sun.spot.peripheral.radio.LowPanHeaderInfo;
import com.sun.spot.peripheral.radio.RadioPacket;
import com.sun.spot.util.IEEEAddress;
import com.sun.spot.util.Utils;
import java.io.IOException;
import java.util.Random;
import org.sunspotworld.PollMobileTask;
import org.sunspotworld.datawrappers.DataWrapperVector;
import org.sunspotworld.mydatawrappers.TrackingPacket;
import org.sunspotworld.mydatawrappers.TrackingPacketFactory;

/**
 *
 * @author me
 */
public class DataPollProtocol implements IProtocolManager {
    private static boolean protocolEnabled = false;
    public static final byte PROTOCOL_NUM = MyProtocols.POLL;
    private static final int PAYLOAD_SIZE = RadioPacket.MIN_PAYLOAD_LENGTH-5;
    
    private static Random random = new Random(new IEEEAddress(System.getProperty("IEEE_ADDRESS")).asLong());
    private static final int RANDOM_BACKOFF = 10;
    private static final int CONSTANT_BACKOFF = 2;
    private static final int BROADCAST_RETRIES = 5;
    private static byte[] buffer = new byte[PAYLOAD_SIZE];
    private static int size = 0;
    private static byte numPkts = 0;
    private int retries = 0;
    
    public static void setEnabled(boolean enabled) {
        protocolEnabled = enabled;
    }
    
    public void processIncomingData(byte[] arg0, LowPanHeaderInfo arg1) {
        System.out.println("Poll received");
        PollMobileTask.reportPoll();
        if (!protocolEnabled) {
            return;
        }
        TrackingPacket packet;
        synchronized (DataWrapperVector.getInstance()) {
            while (!DataWrapperVector.getInstance().isEmpty() && protocolEnabled) {
                size = 1;
                while (!DataWrapperVector.getInstance().isEmpty() && size < PAYLOAD_SIZE - DataWrapperVector.getInstance().getMaxSize()) {
                    //LEDManager.getInstance().toggleLED(3);
                    packet = (TrackingPacket) DataWrapperVector.getInstance().dequeue();
                    System.out.println("Type: " + packet.getType());
                    System.out.println(TrackingPacketFactory.getInstance().printHeader(packet));
                    System.out.println(packet.printEntryLine());
                    //write to packet
                    packet.writeToBuffer(buffer, size);
                    
                    try {
                        System.out.println(TrackingPacketFactory.getInstance().constructDataWrapper(buffer, size).printEntryLine());
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                        
                    size += packet.getSize();
                    numPkts++;
                }
                System.out.println("size: " + size);
                //send packet
                buffer[0] = numPkts;
                sendPacket(arg1.sourceAddress);
            }
        }
    }
    
    private void sendPacket (long toAddress) {
        try {
            System.out.println("Sending data...");
            LowPan.getInstance().sendWithoutMeshingOrFragmentation(MyProtocols.DATA_TRANSFER, toAddress, buffer, 0, size);
            System.out.println("sent");
            size = 1;
            numPkts = 0;
        } catch (NoAckException ex) {
            if (retries < BROADCAST_RETRIES && protocolEnabled) {  //if retried less than 5 times and there's enough time left
                retries++;
                sendPacket(toAddress);
            } else {
                ex.printStackTrace();
            }
        } catch (ChannelBusyException ex) {
            if (protocolEnabled) {  //if there's enough time left
                //retry if channel busy
                Utils.sleep(random.nextInt(RANDOM_BACKOFF) + CONSTANT_BACKOFF);  // wait a random amount before retrying
                sendPacket(toAddress);
            }
        }
        retries = 0;  //retries resets after first recursive call of sendPacket falls through to here
    }
}
